using System;
using System.Text.RegularExpressions;
using RPGOnline.Controls.Chat;
using RPGOnline.Remoting;
using RPGOnline.Remoting.Entities;
using RPGOnline.Remoting.Events;

namespace RPGOnline.Filters
{
    public class DiceRoller : IMessageHandler
    {
        private readonly UserManager m_userManager;
        private Random m_random;
        private Regex m_rollFormat = new Regex(@"^/roll (?<howMany>\d+)d(?<dieSides>\d+)(?<modifiers>(?:(\+\d+)|(\-\d+))?)");
        private Regex m_secretRollFormat = new Regex(@"^/sroll (?<howMany>\d+)d(?<dieSides>\d+)(?<modifiers>(?:(\+\d+)|(\-\d+))?)");
        private Regex m_masterRollFormat = new Regex(@"^/mroll (?<howMany>\d+)d(?<dieSides>\d+)(?<modifiers>(?:(\+\d+)|(\-\d+))?)=(?<result>\d+)");


        public event EventHandler<UserRollEventArgs> OnUserRoll;
        public event EventHandler<UserRollEventArgs> OnUserSecretRoll;
        public event EventHandler<UserRollEventArgs> OnMasterRoll;

        public DiceRoller(UserManager userManager)
        {
            m_userManager = userManager;
            m_random = new Random((int) DateTime.Now.Ticks);
        }

        public RollResult Roll(int howMany, int dieSides, int modifiers)
        {
            RollResult rollResult = new RollResult(howMany, dieSides, modifiers);

            for ( int i = 0; i < howMany; i++ )
                rollResult.AddRoll(m_random.Next(1, dieSides+1));

            return rollResult;
        }

        public RollResult Roll(int howMany, int dieSides, int modifiers, int result)
        {
            return new RollResult(howMany, dieSides, modifiers, result);
        }

        public bool IsValid(string rollFormat)
        {
            return m_rollFormat.IsMatch(rollFormat) || m_secretRollFormat.IsMatch(rollFormat) || m_masterRollFormat.IsMatch(rollFormat);
        }

        public bool Handle(string rollFormat)
        {
            return UserRoll(rollFormat) || SecretRoll(rollFormat) || MasterRoll(rollFormat);
        }

        private bool UserRoll(string rollFormat)
        {
            if (!m_rollFormat.IsMatch(rollFormat))
                return false;

            Match match = m_rollFormat.Match(rollFormat);
            Group howMany = match.Groups["howMany"];
            Group dieSides = match.Groups["dieSides"];
            Group modifiers = match.Groups["modifiers"];

            RollResult result = Roll(
                Convert.ToInt32(howMany.Value),
                Convert.ToInt32(dieSides.Value),
                Convert.ToInt32(modifiers.Success && !string.IsNullOrEmpty(modifiers.Value) ? modifiers.Value : "0")
                );

            if(OnUserRoll != null)
                OnUserRoll(this, new UserRollEventArgs(m_userManager.CurrentUser, result));

            return true;
        }

        private bool SecretRoll(string rollFormat)
        {
            if (!m_secretRollFormat.IsMatch(rollFormat))
                return false;
            
            Match match = m_secretRollFormat.Match(rollFormat);
            Group howMany = match.Groups["howMany"];
            Group dieSides = match.Groups["dieSides"];
            Group modifiers = match.Groups["modifiers"];

            RollResult result = Roll(
                Convert.ToInt32(howMany.Value),
                Convert.ToInt32(dieSides.Value),
                Convert.ToInt32(modifiers.Success && !string.IsNullOrEmpty(modifiers.Value) ? modifiers.Value : "0")
                );

            if (OnUserSecretRoll != null)
                OnUserSecretRoll(this, new UserRollEventArgs(m_userManager.CurrentUser, result));

            return true;
        }

        private bool MasterRoll(string rollFormat)
        {
            if (!m_masterRollFormat.IsMatch(rollFormat) || !m_userManager.IsMaster)
                return false;

            Match match = m_masterRollFormat.Match(rollFormat);
            Group howMany = match.Groups["howMany"];
            Group dieSides = match.Groups["dieSides"];
            Group modifiers = match.Groups["modifiers"];
            Group expectedResult = match.Groups["result"];

            RollResult result = Roll(
                Convert.ToInt32(howMany.Value),
                Convert.ToInt32(dieSides.Value),
                Convert.ToInt32(modifiers.Success && !string.IsNullOrEmpty(modifiers.Value) ? modifiers.Value : "0"),
                Convert.ToInt32(expectedResult.Value)
                );

            if (OnMasterRoll != null)
                OnMasterRoll(this, new UserRollEventArgs(m_userManager.CurrentUser, result));

            return true;
        }
    }
}